(in-package "ACL2")

(include-book "io-utilities" :dir :teachpacks)
(include-book "list-utilities" :dir :teachpacks)
(include-book "binary-io-utilities" :dir :teachpacks)

(include-book "formulas")

(include-book "modified-avl-rational-keys-inner")
(include-book "modified-avl-rational-keys-outer")

(include-book "driver")
(include-book "world" :dir :teachpacks)

  (defun get-random-number (seed)
    (let ((modulo (expt 2 32))
          (multiplier 1103515245)
          (increment 12345)
         )
          (mod (+ (* multiplier seed) increment) modulo)
    )
  )

;create-y
;input: (create-y 110 '(111 112 113))
;output: ((110 . 111) (110 . 112) (110 . 113))
(defun create-y (x ys)
  (if (consp ys)
      (cons (cons x (car ys)) (create-y x (cdr ys)))
      nil)
  )

;create=x
;input: (create-x '(110 111 112) '(113 114 115))
;output: (((110 . 113) (110 . 114) (110 . 115)) ((111 . 113) (111 . 114) (111 . 115)) ((112 . 113) (112 . 114) (112 . 115)))
(defun create-x (xs ys)
  (if (consp xs)
      (cons (create-y (car xs) ys) (create-x (cdr xs) ys))
      nil
     )
  )

;get-score
;will call the method to create the scores of the function
;variables:
;  xs: (first-individual second-individual)
(defun get-score (xs)
  (cons xs 5)
  )

;find-all-combination-helper
(defun find-all-combination-helper (xs)
  (if (consp xs)
      (cons (get-score (car xs)) (find-all-combination-helper (cdr xs)))
      nil)
  )

;find-all-possible-combinations
(defun find-best-combination (xs)
  (if (consp xs)
      (cons (find-all-combination-helper (car xs)) (find-best-combination (cdr xs)))
      nil)
  )

;create-all-possible-combinations
(defun create-all-possible-combinations (xs ys)
  (find-best-combination (create-x xs ys))    
  )

;check-to-stop-switching
(defun check-to-stop-switching (member-list-1 member-list-2)
  nil
  )

;switch-member-between-teams
;parameters
;  input:  avl-tree: complete avl tree
;          worst-team-key: team with the lowest score that we need to try and improve: '(group# score)
;          random-team-key: team that does not have the lowest score but is not necessarily the highest: '(group# score)
;  output: improved avl tree with the switched team numbers
;
(defun switch-member-between-teams (avl-tree worst-team-key random-team-key)
  (avl-retrieve avl-tree worst-team-key)
  )

;compare-scores-between-team-sets-helper
;parameters
;  input:  avl-team: name of 1st team to compare
;          avl-tree: complete avl tree
;  output: returns the score of the avl-team
(defun compare-scores-between-team-sets-helper (avl-team avl-tree)
  (car (cdr (car (avl-retrieve avl-tree avl-team))))
  )

;compare-scores-between-team-sets
;parameters
;  input:  avl-team-1: name of 1st team to compare
;          avl-team-2: name of 2nd team to compare
;          avl-tree: complete avl tree
;  output: the teams avl tree with the better score
;  ex: (avl-retrieve '(2 (1 30) (test value) nil (1 (2 15) (test1 value1) nil nil)) '(1 30)) -> ((1 30) test value)
(defun compare-scores-between-team-sets (avl-team-1 avl-team-2 avl-tree)
  (if (>= (compare-scores-between-team-sets-helper avl-team-1 avl-tree)
          (compare-scores-between-team-sets-helper avl-team-2 avl-tree))
      avl-team-1
      avl-team-2)
  )

  (defun get-random-number-mod-max (seed max)
    (let ((new-seed (get-random-number seed))
         )
          (cons (mod new-seed max) new-seed)
    )
  )

(defun form-groups (list-of-students seed avl-tree)
  (if (consp list-of-students)
      (form-groups (car list-of-students) seed (avl-insert avl-tree (get-random-number-mod-max (car seed) (car (cdr seed))) (car list-of-students)))
      avl-tree
      )
  )

(defun compare-student-id (value x y)
  (if (consp x)
      (if (char-equal (car x) (car y))
          (compare-student-id t (cdr x) (cdr y))
          nil)
      value)
  )

;compare-students
;  input: 
;
; takes in a list and an item to compare.  this item to compare is the entire the student list.  will compare student id's.  returns position that student is in
(defun compare-students-and-return-pos (i x xs)
  (if (consp xs)
      (if (compare-student-id t (car x) (caar xs))
          i
          (compare-students-and-return-pos (+ i 1) x (cdr xs)))
      nil
      )
  )

;remove-nth-student-helper
(defun remove-nth-student-helper (i pos xs)
  (if (= i pos)
      nil
      (car xs)
      )
  )

;remove-nth-student
;removes the student specified
(defun remove-nth-student (i pos xs)
  (if (consp xs)
      (remove nil (cons (remove-nth-student-helper i pos xs) (remove-nth-student (+ i 1) pos (cdr xs))))
      nil
  )
)

;randomize-list
(defun randomize-list (seed list)
  (if (consp list)
      (cons (nth (car (get-random-number-mod-max seed (len list))) list)
            (randomize-list (car (get-random-number-mod-max seed (len list))) (remove-nth-student 0 (car (get-random-number-mod-max seed (len list))) list)))
      nil))


;remove-recurrences-helper
(defun remove-recurrence-helper (x ys)
  (if (consp ys)
      ;(if (not (string-equal (chrs->str (car x)) (chrs->str (caar ys))))
      (if (not (string-equal (chrs->str (car x)) (chrs->str (caar ys))))
          (cons (car ys) (remove-recurrence-helper x (cdr ys)))
          (remove-recurrence-helper x (cdr ys)))
nil))
  
;remove-recurrence
;input: (remove-recurrence (car (randomize-list 30 (get-students-as-data "input.txt"))) (randomize-list 30 (get-students-as-data "input.txt")))
(defun remove-recurrence (xs ys)
  (if (consp xs)
      (remove-recurrence (cdr xs) (remove-recurrence-helper (car xs) ys))
  ys))

;inner-iterator
; puts all items from list into avl-tree and organizes them by student id
; (inner-iterator (get-students-as-data "input.txt"))
(defun inner-iterator (inner-tree list)
  (if (consp list)
      (avl-insert-inner 
          (inner-iterator 
              inner-tree 
              (cdr list))
          (chrs->str (caar list))
          (cdr (car list)))
      nil))

;create-initial-teams
;(avl-flatten (create-initial-teams 0 3 (empty-tree)))
;(((0 . 0) "no tree") ((1 . 0) "no tree") ((2 . 0) "no tree"))
(defun create-initial-teams (i num-teams outer-tree)
  (if (< i num-teams)
      (avl-insert (create-initial-teams 
                   (+ i 1)
                   num-teams
                   outer-tree
                   )
                  (cons i (list 0))
                  (list "no tree")
                  )
      nil))

;random-student-from-list
(defun random-student-from-list (list-of-students seed)
  (let ((first-part (car (break-at-nth (car (get-random-number-mod-max seed 
                                       (len list-of-students))) list-of-students)))
        (second-part (cdadr (break-at-nth (car (get-random-number-mod-max seed 
                                       (len list-of-students))) list-of-students)))
        (next-student (caadr (break-at-nth (car (get-random-number-mod-max seed 
                                       (len list-of-students))) list-of-students))))
    (list next-student (append first-part second-part) (cdr (get-random-number-mod-max seed 
                                       (len list-of-students))))
  )
)

;groups-from-list-of-students
; Call using initial-group
; ie (groups-from-list-of-students '("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k") (initial-groups 4) 4 0 55235)
;(groups-from-list-of-students (avl-flatten-inner (inner-iterator 3 (get-students-as-data "input.txt"))) (initial-groups 4) 4 0 55235)
(defun groups-from-list-of-students (list-of-students groups num-groups cur-group seed)
  (if (consp list-of-students)
      (let ((first-part (car (break-at-nth (mod cur-group num-groups) groups)))
            (second-part (cdadr (break-at-nth (mod cur-group num-groups) groups)))
            (next-group (caadr (break-at-nth (mod cur-group num-groups) groups)))
            (next-student (car (random-student-from-list list-of-students seed)))
            (next-student-list (cadr (random-student-from-list list-of-students seed)))
            (next-seed (caddr (random-student-from-list list-of-students seed))))
            (groups-from-list-of-students next-student-list 
               (append first-part (list (cons next-student next-group)) second-part)
                num-groups (+ 1 cur-group) seed)
      )
      groups
  )
)

;throw-into-tree-helper
;(throw-into-tree-helper 0 (len (car (groups-from-list-of-students (avl-flatten-inner (inner-iterator 3 (get-students-as-data "input.txt"))) (initial-groups 4) 4 0 55235))) (car (groups-from-list-of-students (avl-flatten-inner (inner-iterator 3 (get-students-as-data "input.txt"))) (initial-groups 4) 4 0 55235)) (empty-tree-inner))
(defun throw-into-tree-helper (i len-list inner-masterlist avl-inner)
  (if (< i (+ (len inner-masterlist) 1))
      (avl-insert-inner (throw-into-tree-helper (+ i 1) len-list (cdr inner-masterlist) avl-inner) (caar inner-masterlist) (cdr (car inner-masterlist)))
      nil))

;throw-into-tree
;(throw-into-tree 0 4 (groups-from-list-of-students (avl-flatten-inner (inner-iterator 3 (get-students-as-data "input.txt"))) (initial-groups 4) 4 0 55235) (empty-tree-inner))
(defun throw-into-tree (i num-groups masterlist avl-inner avl-outer)
  (if (< i num-groups)
      (avl-insert (throw-into-tree (+ i 1) num-groups (cdr masterlist) avl-inner avl-outer) (list i 0) (throw-into-tree-helper 0 (len (car masterlist)) (car masterlist) (empty-tree-inner)))
      nil))

;initial-groups
(defun initial-groups (num-groups)
  (if (not (equal num-groups 0))
      (append (list (list nil)) (initial-groups (- num-groups 1)))
      nil
  )
)

;store-total-loops
(defun store-total-loops (i max)
  (if (< i max)
      (cons 1 (store-total-loops (+ i 1) max))
      nil))

;return-flat-inner-tree
(defun return-flat-inner-tree (i score avl-tree)
  (avl-retrieve avl-tree (list i score))
  )

;return-flat-outer-tree
(defun return-flat-outer-tree (avl-tree)
  (avl-flatten avl-tree)
  )

;return-largest-key-pair
(defun return-largest-key-pair (avl-tree seed)
  (let ((worst-team (caar (return-flat-outer-tree avl-tree)))
        (rest-of-them (cdr (return-flat-outer-tree avl-tree))))
        (list worst-team (caaadr (break-at-nth 
                                  (car (get-random-number-mod-max seed (len rest-of-them))) rest-of-them)))
  )
)

(defun return-top-key-pair (avl-tree)
  (caar (return-flat-outer-tree avl-tree)))

(defun calculate-team-score-temp (a b c d)
  (list a (car (cdr '((2 0) 30)))))

;(calculate-team-score (list i 0) (avl-flatten-inner (cdr (avl-retrieve (initialize-teams (+ i 1) master-avl list-of-actual-weights specifications)
;(defun initialize-teams (i num-teams master-avl list-weights spec avl-tree)
;  (avl-insert (avl-delete master-avl (list i 0))
;              (list i (car (cdr (calculate-team-score-temp (list i 0) (avl-flatten-inner (cdr (avl-retrieve master-avl (list i 0)))) list-weights spec))))
;              (cdr (avl-retrieve master-avl (list i 0))))
;  )

(defun initialize-teams (i num-teams master-avl list-weights spec avl-tree)
  (if (< i num-teams)
      (avl-insert (initialize-teams (+ i 1) num-teams (avl-delete master-avl (list i 0)) list-weights spec avl-tree)
                  (list i (car (cdr (calculate-team-score-temp (list i 0) (avl-flatten-inner (cdr (avl-retrieve master-avl (list i 0)))) list-weights spec))))
                  (cdr (avl-retrieve master-avl (list i 0))))
      nil)
  )


;(defun return-all-flattened-inner (i avl-outer-size avl-tree)
;  (if (< i size)
;      (avl-retrieve
                  
;form-initial-tree
;parameters
;  input:  list-of-students: complete list of all the students
;          list-of-spec: all the parameters that belong to each student
;          seed:  seed for random number generator
;  output: complete avl tree with randomized teams   

;(form-initial-tree (get-students-as-data "input.txt") 4 0 0 23434)

;(("SKILL SET" 2/5 ("java" "c/c++" "haskell" "acl2")) ("team interaction skills" 3/5 ("communication and negotiation" "analytic and creative" "organization")))
;(0.3 0.4 0.2 0.8)
(defun form-initial-tree (list-of-students num-teams list-of-actual-weights specifications seed)
  (throw-into-tree 0 num-teams (groups-from-list-of-students (avl-flatten-inner (inner-iterator 0 list-of-students)) (initial-groups num-teams) num-teams 0 seed) (empty-tree) (empty-tree-inner))
 )